package com.xxhg;

import org.apache.commons.math3.stat.regression.OLSMultipleLinearRegression;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;

public class MultivariateLinearRegressionExample {

    public static void main(String[] args) {
        // 读取 Excel 文件
        String excelFilePath = "D:\\xibike\\回归算法测试数据.xlsx";
        double[][] x = readExcelFile(excelFilePath);

        //对阀门开度进行归一化处理
        double[] normalizedOpenness = new double[x.length - 1];
        for (int i = 1; i < x.length; i++) {
            normalizedOpenness[i - 1] = normalize(x[i][3], 0, 100);
        }
        System.out.println(" normalizedOpenness: " + Arrays.toString(normalizedOpenness));
        for (int i = 1; i < x.length; i++) {
            x[i][3] = normalizedOpenness[i - 1];
        }
        // 输出特征值，跳过第一行（标题行）
        System.out.println("特征值:");
        for (int i = 1; i < x.length; i++) {
            System.out.println(Arrays.toString(x[i]));
        }

        // 读取目标变量（室温）
        double[] y = readTargetVariable(excelFilePath);
        System.out.print("目标变量 y: [");

        // 输出目标变量，跳过第一行（标题行）
        for (int i = 1; i < y.length; i++) {
            System.out.print(" "+y[i]+" ");
        }
        System.out.println("]");

        // 创建多元线性回归对象
        OLSMultipleLinearRegression regression = new OLSMultipleLinearRegression();

        // 设置样本数据
        regression.newSampleData(y, x);

        // 获取回归系数
        double[] coefficients = regression.estimateRegressionParameters();
        System.out.println("回归系数: " + Arrays.toString(coefficients));

        // 预测新数据点 回水 供水 室外温度 开度
        double[] newX = {35.46, 39.79, 9, 100};
        newX[3]= normalize(newX[3], 0, 100);
        double predictedY = predict(regression, newX);
        System.out.println("预测值: " + predictedY);
    }

    // 读取 Excel 文件中的特征值
    private static double[][] readExcelFile(String filePath) {
        try (FileInputStream fis = new FileInputStream(filePath);
             Workbook workbook = new XSSFWorkbook(fis)) {

            Sheet sheet = workbook.getSheetAt(0);
            int rowCount = sheet.getLastRowNum()+1;
            int columnCount = 4; // 只读取前四列作为特征值

            double[][] data = new double[rowCount][columnCount];

            for (int i = 1; i < rowCount; i++) {
                Row row = sheet.getRow(i);
                for (int j = 0; j < columnCount; j++) {
                    Cell cell = row.getCell(j);
                    if (cell != null) {
                        data[i][j] = cell.getNumericCellValue();
                    } else {
                        data[i][j] = 0.0; // 处理空单元格
                    }
                }
            }

            return data;

        } catch (IOException e) {
            e.printStackTrace();
            return new double[0][0];
        }
    }

    // 读取 Excel 文件中的目标变量（室温）
    private static double[] readTargetVariable(String filePath) {
        try (FileInputStream fis = new FileInputStream(filePath);
             Workbook workbook = new XSSFWorkbook(fis)) {

            Sheet sheet = workbook.getSheetAt(0);
            int rowCount = sheet.getLastRowNum() +1;
            int targetColumnIndex = 4; // 第四列作为目标变量

            double[] target = new double[rowCount];

            for (int i = 1; i < rowCount; i++) {
                Row row = sheet.getRow(i);
                Cell cell = row.getCell(targetColumnIndex);
                if (cell != null) {
                    target[i] = cell.getNumericCellValue();
                } else {
                    target[i] = 0.0; // 处理空单元格
                }
            }

            return target;

        } catch (IOException e) {
            e.printStackTrace();
            return new double[0];
        }
    }

    // 手动实现预测方法
    private static double predict(OLSMultipleLinearRegression regression, double[] newX) {
        double[] coefficients = regression.estimateRegressionParameters();
        double predictedY = 0.0;

        // 添加截距项
        double[] newXWithIntercept = new double[newX.length + 1];
        newXWithIntercept[0] = 1.0;
        System.arraycopy(newX, 0, newXWithIntercept, 1, newX.length);

        for (int i = 0; i < newXWithIntercept.length; i++) {
            predictedY += coefficients[i] * newXWithIntercept[i];
        }

        return predictedY;
    }
    private static double normalize(double value, double min, double max) {
        return (value - min) / (max - min);
    }
}